package uk.ac.sanger.dasregistry.timer;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import org.biojava.dasobert.das2.io.DasSourceReaderImpl;
import org.biojava.dasobert.dasregistry.Das1Validator;
import org.biojava.dasobert.dasregistry.DasSource;
import org.biojava.services.das.dao.DasServer;
import org.biojava.services.das.dao.DasServerDAO;
import org.biojava.services.das.dao.ServerManager;
import org.biojava.services.das.dao.DasSourceManager;
import org.biojava.services.das.registry.ConfigBean;
import org.biojava.services.das.registry.DasRegistry;
import org.biojava.services.das.registry.DasRegistrySql;
import org.biojava.services.das.registry.UserManager;
import org.biojava.services.das2.Das2Mirror;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import dasregistry.utils.MachineInfo;

public class CleanRegistry {

	DasSourceManager dasSourceManager;
	DasServerDAO dasServerManager;
	UserManager userManager;

	public DasSourceManager getDasSourceManager() {
		return dasSourceManager;
	}

	public void setDasSourceManager(DasSourceManager dasSourceManager) {
		this.dasSourceManager = dasSourceManager;
	}

	public DasServerDAO getDasServerManager() {
		return dasServerManager;
	}

	public void setDasServerManager(DasServerDAO dasServerManager) {
		this.dasServerManager = dasServerManager;
	}

	public UserManager getUserManager() {
		return userManager;
	}

	public void setUserManager(UserManager userManager) {
		this.userManager = userManager;
	}

	public void setRegistry(DasRegistrySql registry) {
		this.registry = registry;
	}

	public static final String VERSION_REGEX = "([a-zA-Z_0-9]*?)([0-9\\\\.]*+)?$";

	static Pattern versionPattern = Pattern.compile(VERSION_REGEX);
	DasRegistrySql registry;

	public CleanRegistry() {

	}

	public boolean cleanServers() {

		// List<DasSource> sources = registry.listServices();
		// Map sangerSources=new HashMap();
		// Map ensemblSources=new HashMap();
		// List <DasSource> deletionList=new ArrayList();
		// //list all servers that have das.ensembl.org
		// //list all sources that have das.sanger.ac.uk
		// for(DasSource source:sources){
		// System.out.println("checking url:"+source.getUrl());
		// String dsn=Das1Validator.getDataSourceNameFromUrl(source.getUrl());
		// System.out.println(dsn);
		// if(source.getUrl().contains("das.sanger.ac.uk")){
		//				
		// sangerSources.put(dsn, source);
		// }
		// if(source.getUrl().contains("das.ensembl.org")){
		// ensemblSources.put(dsn, source);
		// }
		// }
		// //see where datasource names are the same
		// Set keys = sangerSources.keySet();
		// Iterator it = keys.iterator();
		// while(it.hasNext()){
		// String key=(String) it.next();
		// if(ensemblSources.containsKey(key)){
		// deletionList.add((DasSource) sangerSources.get(key));
		// }
		// }
		// //remove sources that have a match from das.sanger.ac.uk
		// for(DasSource delete:deletionList){
		// System.out.println(delete.getUrl());
		// }
		// System.out.println("number to be deleted="+deletionList.size());
		// registry.archiveServers(deletionList);

		// use sql statement to replace all das.ensembl urls with
		// das.sanger.ac.uk

		MachineInfo machine = new MachineInfo();
		// mib21789i
		if (machine.isMachineForJob("cleanRegistry")) {
			DataSource ds = registry.getDataSource();
			Connection conn = null;

			try {
				conn = ds.getConnection();

				// get configured mirrors from the configuration - should be
				// able to delete this after ensembl updates to using no prefix
				// ids from registry
				// no as these are in the registry table already and have das
				// sources
				// Set<String> configUrls = getConfiguredUrls();
				// get unique servers from the registry table
				Set<String> rootUrls = dasServerManager
						.getUniqueServersFromSources(conn);
				// rootUrls.addAll(configUrls);
				// populate the server table with new servers (from sources that
				// have been registered through the interface)
				dasServerManager.populateServerTable(rootUrls);
				// need to also add server_id to the data sources to associate
				// them with the server
				populateServer_idsIntoRegistryTable(conn);
				// clean by getting unique server and if in server table there
				// is an user_id then get all data sources with the server_id
				List<DasServer> servers = dasServerManager.getDasServers();
				// and see if some of them are not in the sources document
				// anymore
				for (DasServer server : servers) {
					if (server.getUserId() != 0) {
						// && !server.getUrl().equals(
						// "http://www.ensembl.org/das/")) {// ensembl
						// not
						// currently
						// owned
						// and
						// we
						// want
						// it to
						// be
						// left
						// as is
						// apart
						// from
						// some
						// deleted
						// until
						// dependency
						// on
						// prefix
						// ids
						// gone
						// get the sources from the sources document
						System.out
								.println("cleaning server " + server.getUrl());
						DasSourceReaderImpl reader = new DasSourceReaderImpl();
						URL readingUrl = null;
						try {
							readingUrl = new URL(server.getUrl() + "sources");
						} catch (MalformedURLException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}// need sources command on the end as for validation it
						// puts it on but not here
						// System.out.println("testing sources for cleaning:"+readingUrl);
						DasSource[] sources = reader.readDasSource(readingUrl);
						System.out.println("number of sources="
								+ sources.length);
						// if(sources.length>1)
						// get all the sources from the registry table with that
						// server_id
						List<DasSource> serverSources = registry
								.listServicesByServer(server.getServerId());
						// System.out.println("server sources from reg size="+serverSources.size());
						List<DasSource> oldSources = this.getOldSources(
								serverSources, sources);
						// if(sources.)
						for (DasSource oldSource : oldSources) {

							System.out.println("old source for archiving="
									+ oldSource.getUrl());
						}
						registry.archiveServers(oldSources);
						// System.out.println("old sources size="+oldSources.size());
						// if some in the registry table that are not in the
						// sources document archive them
						// registry.archiveServers(oldSources);
						dasServerManager.updateSourceNumbers(server.getUrl(),
								sources.length);
					}
					List<DasSource> serverSources = registry
							.listServicesByServer(server.getServerId());
					dasServerManager.updateSourceNumbers(server.getUrl(),
							serverSources.size());
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return false;
			} finally {
				try {
					conn.close();

				} catch (SQLException e) {
					e.printStackTrace();

				}
			}
		}
		return true;
		// if not then archive that data source and remove it.
	}

	private List<DasSource> getOldSources(List<DasSource> regSources,
			DasSource[] sourcesSources) {
		List<DasSource> oldSources = new ArrayList<DasSource>();
		Map<String, DasSource> sourcesDocSources = new HashMap<String, DasSource>();

		for (DasSource sourcesSource : sourcesSources) {
			sourcesDocSources.put(sourcesSource.getUrl(), sourcesSource);
		}
		// if registry source not in the sources document source list return it
		// in the list
		for (DasSource regSource : regSources) {
			if (!sourcesDocSources.containsKey(regSource.getUrl())) {
				oldSources.add(regSource);
			}

		}

		return oldSources;
	}

	private void populateServer_idsIntoRegistryTable(Connection conn) {
		try {
			List<DasSource> sources = dasSourceManager
					.getAllSources(conn, null);
			for (DasSource source : sources) {
				// loop through and see if there is a user_id indicating it's a
				// mirrored source
				// if there is then add
				String sourceUrl = source.getUrl();
				// trim off the dsn and see if there is a server matching with a
				// user_id
				String rootUrl = Das1Validator
						.removeDataSourceNameFromUrl(sourceUrl);

				DasServer server = dasServerManager
						.getServerForServerUrl(rootUrl);
				// int user_id=dsm.getUserForServerUrl(conn, rootUrl);
				// if(user_id!=0){
				dasSourceManager.addServerIdToSource(conn, sourceUrl, server
						.getServerId());

				// }

			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	// private Set<String> getConfiguredUrls() {
	// Mirroring mirroring=new Mirroring();
	// List<Das2Mirror> mirrors = mirroring.getMirrorServers();
	// Set<String>configUrls=new HashSet<String>();
	// for(Das2Mirror mirror:mirrors){
	// configUrls.add(mirror.getUrl());
	//			
	// }
	// return configUrls;
	// }

	private DasRegistry getRegistry() {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"config_dasregistry.xml");
		DasRegistry registryClient = (DasRegistry) context
				.getBean("dasRegistryClient");
		return registryClient;
	}

}
